<!DOCTYPE html>
<html lang="en">
  <head>
    <meta charset="UTF-8" />
    <meta http-equiv="X-UA-Compatible" content="IE=edge" />
    <meta name="viewport" content="width=device-width, initial-scale=1.0" />
    <title>垃圾</title>
  </head>
  <body>
    “可达”值是那些以某种方式可访问或可用的值。它们一定是存储在内存中的。 当前函数的局部变量和参数。 嵌套调用时，当前调用链上所有函数的变量与参数。 全局变量。 （还有一些内部的） 这些值被称作
    根（roots）。 2如果一个值可以通过引用或引用链从根访问任何其他值，则认为该值是可达的。 在 JavaScript 引擎中有一个被称作 垃圾回收器
    的东西在后台执行。它监控着所有对象的状态，并删除掉那些已经不可达的。

    <script>
      // user 具有对这个对象的引用
      // debugger
      let user = {
        name: 'John'
      }

      let admin = user
      user = null

      // 关于对象不存在的“属性”的问题
      /*   举个例子，假设我们有很多个 user 对象，其中存储了我们的用户数据。
    我们大多数用户的地址都存储在 user.address 中，街道地址存储在 user.address.street 中，但有些用户没有提供这些信息。 在这种情况下，当我们尝试获取 user.address.street，而该用户恰好没提供地址信息，我们则会收到一个错误： */
      // let user = {} // 一个没有 "address" 属性的 user 对象

      // alert(user.address.street) // Error!  Cannot read property 'address' of null

      // user.address 为 undefined，尝试读取 user.address.street 会失败，并收到一个错误。

      user = {
        name: 'John'
        // address: '阿富汗'
      }

      console.log(user.address && user.address)
      // alert(user.address ? user.address.street : undefined)
      // alert(user.address ? (user.address.street ? user.address.street.name : null) : null)
      // alert(user.address && user.address.street && user.address.street.name) // undefined（不报错）

      alert(user?.address?.street) // undefined（不报错）

      //  ?. 前的变量必须已声明（例如 let/const/var user 或作为一个函数参数）。可选链仅适用于已声明的变量。

      // 如果 ?. 左边部分不存在，就会立即停止运算（“短路效应”）。

      // 所以，如果后面有任何函数调用或者副作用，它们均不会执行。
      user = null
      let x = 0

      user?.sayHi(x++) // 没有 "sayHi"，因此代码执行没有触达 x++

      alert(x) // 0，值没有增加

      let userAdmin = {
        admin() {
          alert('I am admin')
        }
      }

      let userGuest = {}
      /* 可选链 ?. 不是一个运算符，而是一个特殊的语法结构。它还可以与函数和方括号一起使用。
例如，将 ?.() 用于调用一个可能不存在的函数。 */
      userAdmin.admin?.() // I am admin

      userGuest.admin?.() // 啥都没有（没有这样的方法）

      let user1 = {
        firstName: 'John'
      }

      let user2 = null // 假设，我们不能授权此用户

      let key = 'firstName'

      alert(user1?.[key]) // John
      alert(user2?.[key]) // undefined

      alert(user1?.[key]?.something?.not?.existing) // undefined
      // 将 ?. 跟 delete 一起使用：

      delete user?.name // 如果 user 存在，则删除 user.name

      let user = null

      user?.name = 'John' // Error，不起作用
      // 因为它在计算的是 undefined = "John"
    </script>
  </body>
</html>
